package proxy;

import net.sf.cglib.proxy.Enhancer;
import proxy.api.ITrainStation;
import proxy.cglib.CglibInterceptor;
import proxy.java.JdkHandler;
import proxy.staticproxy.TrainStationProxy;
import proxy.target.TrainStation;
import proxy.target.TrainStationNoneImpl;

import java.lang.reflect.Proxy;

/**
 * /usr/libexec/java_home -V
 * java home /Library/Java/JavaVirtualMachines/jdk-11.0.12.jdk/Contents/Home/lib
 *
 * HSDB
 * /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/bin/jhsdb hsdb
 */
public class ProxyMain {
    public static void main(String[] args) throws InterruptedException {

        printBegin("static");
        // 静态代理-编译时代理类已经确定，直接new的方式生成代理类对象（组合，注入接口实现）
        TrainStation trainStation = new TrainStation();
        TrainStationProxy staticProxy = new TrainStationProxy(trainStation);
        staticProxy.sell();
        printEnd("static");

        printBegin("JDK dynamic");
        // JDK动态代理-运行时生成代理类，通过生成的代理类反射生成代理类对象（组合，注入接口实现）
        // JDK动态代理是面向接口的代理模式，目标对象new TrainStation()实现了接口ITrainStation
        // handler对目标方法进行了增强
        ITrainStation dynamicProxy = (ITrainStation) Proxy.newProxyInstance(ProxyMain.class.getClassLoader(), trainStation.getClass().getInterfaces(), new JdkHandler(new TrainStation()));
        dynamicProxy.sell();
        printBegin("JDK dynamic");

        printBegin("Cglib dynamic");
        // Cglib动态代理（继承目标类，重写目标类的（非final）方法）
        Enhancer enhancer = new Enhancer();
        // 设置目标类，目标类没有实现接口，目标类不能用final修饰，目标类方法如果用final修饰也不能被代理
        enhancer.setSuperclass(TrainStationNoneImpl.class);
        // 设置拦截器对象，对目标类进行了增强
        enhancer.setCallback(new CglibInterceptor());
        // 创建子类，即代理
        TrainStationNoneImpl cglibProxy = (TrainStationNoneImpl) enhancer.create();
        cglibProxy.sell();
        printEnd("Cglib dynamic");

        Thread.sleep(1000 * 60 * 10);
    }

    private static void printBegin(String scope) {
        System.out.println("/***************** " + scope + " begin *******************/");
    }

    private static void printEnd(String scope) {
        System.out.println("/***************** " + scope + " end *******************/");
    }
}
